'''
创意大数据项目-数据字典处理
将Excel数据字典转成Word
2021年01月08日
Zhaoys
'''
import math
# Excel依赖
import os, xlrd
import pandas as pd
# word依赖
from docx.enum.style import WD_STYLE_TYPE
from docx import Document
from docx.shared import Cm,Pt,RGBColor,Inches
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.enum.table import WD_ALIGN_VERTICAL                                                                           # 设置对其方式
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_BREAK
from docx.oxml.ns import qn                                                                                             # 设置字体
import time
import logging
from logging import handlers

# 全局常量和变量
file_dir = 'D:\\WordCode\\python\\DwDataHandle\\DataFile\\'
file_res_dir = 'D:\\WordCode\\python\\DwDataHandle\\DataFileRes\\'
#wd_fontName = u'仿宋_GB2312'
wd_fontName = u'方正仿宋_GBK'
company_name = '四川信通平台应用支撑中心'
wd_time = '2021年1月'
wd_fileName = ''
bigCount = 0
flag = 0
'''
# 获取指定目录下的所有文件及文件名
'''
class DwFileNameGet(object):
    def file_name(self):
        global file_dir
        file_list = []
        for root, dirs, files in os.walk(file_dir):
            print('当前目录路径->>',root)                                                                                # 当前目录路径
            print('当前路径下所有子目录->>',dirs)                                                                         # 当前路径下所有子目录
            print('当前路径下所有非目录子文件->>',files)                                                                  # 当前路径下所有非目录子文件
            for index in range(0,len(files)):
                file_path = root+'\\'+files[index]
                file_list.append(file_path)
        return file_list

'''
# 获取Excel数据并筛选
'''
class DwExcelGet(object):
    def DwExcelHandle(self,file_nameS,file_count):
        global flag
        print('当前处理Excel文件->>',file_nameS)
        if file_nameS!='':
            workbook = xlrd.open_workbook(file_nameS)                                                                   # 获取文件对象
            sNameS = workbook.sheet_names()[0]                                                                          # 查看文件中所有的工作表名
            sheet = workbook.sheet_by_index(0)                                                                          # sheet索引从0开始
            rowN = sheet.nrows                                                                                          # sheet中行数
            colN = sheet.ncols                                                                                          # sheet中列数
            print('当前Excel文件信息->>', sheet.name, rowN, colN)

            # Excel数据筛选、分组处理
            df = pd.read_excel(file_nameS, sheet.name)
            df = df[(df.表类型 == '业务表')]                                                                             # 条件筛选 条件拼接使用&或||符号
            if len(df)>0:                                                                                               # 判断是否有数据
                flag = 1                                                                                                # flag = 为有数据
                df = pd.DataFrame(df, columns=['部门名称', '系统名称', '表英文名', '表中文名', '表注释', '字段英文名', '字段中文名','字段类型','字段长度','表类型','字段注释']) # 需要获取的字段数据
                #df['字段类型和长度'] = df['字段类型'] + df['字段长度']
                df['字段类型和长度'] = df.apply(lambda row: DwExcelGet().my_point(row['字段类型'], row['字段长度']), axis=1)

                df = df.reset_index(drop=True)
                system_name = df.loc[1, ['系统名称']]
                system_nameV = str(system_name['系统名称']).replace('系统','')
                df = df.groupby(by='表英文名')
                #df = df.sort_values(by='课程名称')                                                                          # 排序
                #df = df.reset_index(drop=True)                                                                             # 重建索引
                DwWordGet().DwWordCsh(system_nameV)                                                                         # 文档初始化
                count = 1                                                                                                   # 统计分组数据
                count_total = str(len(df.size().index))
                for name, group in df:                                                                                      # name:表英文名  group:分组数据
                    print('表名->>',name)
                    group = group.reset_index(drop=True)
                    #if name == 'ALL_E_MP_CUR_CURVE':
                    #if count <2:
                    DwWordGet().DwwordWrite(count, name, group, system_nameV,file_count,count_total)
                    count = count+1
            else:
                print('没有获取到对应的文件夹或文件名!')
            print("Excel->Word文件处理完成！")

    def my_point(self,colA,colB):                                                                                             # dataFram 数据列拼接合并处理
        colA = str(colA)
        colC = colA
        if str(colB)!='' and str(colB)!='nan':
            colB = str(colB).replace('(','').replace(')','')
            colC = colA+'('+str(colB).replace('.0','')+')'
        return colC

'''
# 将获取的Excel数据写入到Word
'''
class DwWordGet(object):
    # 文档初始化
    def DwWordCsh(self,system_nameV):
        global document,wd_fontName,company_name,wd_time
        #document = Document()                                                                                           # 初始化文档
        document = Document(str(file_dir)+'..\\WdTemplate.docx')
        # 文档统一样式 仿宋_GB2312
        document.styles['Normal'].font.name = wd_fontName
        document.styles['Normal'].font.size = Pt(10)
        document.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), wd_fontName)

        '''
        # document.add_heading('用电信息采集系统（国网标准）数据字典手册', level=0)
        # 首页添加大标题及样式
        title_str = str(system_nameV+'系统数据字典手册')
        title = document.add_paragraph(title_str)
        document.paragraphs[0].runs[0].bold = True                                                                      # 段落加粗
        document.paragraphs[0].runs[0].font.size = Pt(30)                                                               # 段落字号
        document.paragraphs[0].runs[0].font.color.rgb = RGBColor(0, 0, 0)                                               # 段落颜色
        title.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER                                                    # 段落居中
        title.paragraph_format.line_spacing = 1.0                                                                       # 行间距 注意用浮点数 2.0就表示两倍行间距
        title.paragraph_format.space_before = Pt(120)                                                                   # 段前间距
        title.paragraph_format.space_after = Pt(120)                                                                    # 段后间距

        # 首页添加公司及样式
        company = document.add_paragraph(company_name)
        #document.paragaphs[0].runs[0].bold = True                                                                      # 段落加粗
        document.paragraphs[1].runs[0].font.size = Pt(18)                                                               # 段落字号
        document.paragraphs[1].runs[0].font.color.rgb = RGBColor(0, 0, 0)                                               # 段落颜色
        company.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER                                                  # 段落居中
        company.paragraph_format.line_spacing = 1.0                                                                     # 行间距 注意用浮点数  2.0就表示两倍行间距
        company.paragraph_format.space_before = Pt(320)                                                                 # 段前间距
        #company.paragraph_format.space_after = Pt(120)                                                                 # 段后间距

        # 首页添加时间及样式
        time = document.add_paragraph(wd_time)
        document.paragraphs[2].runs[0].font.size = Pt(18)                                                               # 段落字号
        document.paragraphs[2].runs[0].font.color.rgb = RGBColor(0, 0, 0)                                               # 段落颜色
        time.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER                                                     # 段落居中
        time.paragraph_format.line_spacing = 1.0                                                                        # 行间距 注意用浮点数  2.0就表示两倍行间距
        #time.paragraph_format.space_before = Pt(120)                                                                   # 段前间距
        #time.paragraph_format.space_after = Pt(120)                                                                    # 段后间距

        # 首页分页处理
        # 换页只需要把docx.enum.text.WD_BREAK.PAGE作为唯一的参数传递给add_break
        # 如果是换行的话就不需要使用docx.enum.text.WD_BREAK.PAGE参数
        document.paragraphs[2].runs[0].add_break(WD_BREAK.PAGE)                                                         # 分页（在第三段落后分页）
        '''

        # 针对文档中特殊文字设置样式
        for paragraph in document.paragraphs:
            for run in paragraph.runs:
                if '系统数据字典手册' in run.text:
                    title_str = str(system_nameV + '系统数据字典手册')
                    run.text =  run.text.replace('系统数据字典手册',title_str)


    # 文档写入
    def DwwordWrite(self, count, name, group, system_nameV,file_count,count_total):
        global document
        global wd_fontName
        global file_dir
        global wd_fileName
        global bigCount
        df2 = group

        if count == 1:
            document.add_page_break()

        # 正文标题插入
        countV = str(count)
        # Word插入标题相关拼接信息 eg:(118) D_CHGINFO_CATA【档案变更目录表】 该表是对档案变更目录表的信息记录。
        #wd_fileName = str(file_res_dir+'\\'+str(file_count)+'.'+system_nameV+'系统数据资源手册.docx')
        wd_fileName = str(file_res_dir + '\\'+ system_nameV + '系统数据资源手册.docx')
        head_str = str('(' + countV + ') ' + name)                                                                      # 每组数据对应一级标题名称
        zw_str = ''                                                                                                     # 每组数据对应正文内容
        if len(df2)>1:                                                                                                  # 如果数据行为空的则不进行数据写入处理
            table_name = df2.loc[1,['表中文名']]
            table_comments = df2.loc[1,['表注释']]
            table_nameV = str(table_name['表中文名'])
            table_commentsV= str(table_comments['表注释'])
            if table_nameV != 'nan':                                                                                    # 判断是否为'nan'==''
                if table_commentsV != 'nan':
                    head_str = str('('+countV+') '+name+'【'+table_nameV+'】')
                    #zw_str = str('    该表是对'+table_commentsV+'的信息记录。')
                    zw_str = str('    ' + table_commentsV)
                else:
                    head_str = str('('+countV+') '+name+'【'+table_nameV+'】')
        #oneLevel = document.add_heading(head_str, level=1)
        oneLevel = document.add_heading('', level=1).add_run(head_str)                                                  # 标题内容
        oneLevel.font.name = wd_fontName                                                                                # 标题字体
        oneLevel._element.rPr.rFonts.set(qn('w:eastAsia'), wd_fontName)
        oneLevel.font.size = Pt(16)                                                                                     # 标题字体大小
        oneLevel.font.color.rgb = RGBColor(0, 0, 0)                                                                     # 标题字体颜色

        if zw_str!='':
            #countV_Now = str(int(countV) + 3)                                                                          # 当前段落编号（含首页）
            #document.paragraphs[0].runs[0].add_break()                                                                 # 换行
            #oneLevel.add_break()
            wd_comment = document.add_paragraph().add_run(zw_str)                                                       # 增加行（表注释）
            wd_comment.font.name = wd_fontName                                                                        # 标题字体
            wd_comment.font.size = Pt(14)                                                                               # 段落字号
            wd_comment.font.color.rgb = RGBColor(0, 0, 0)                                                               # 段落颜色
            wd_comment.alignment = WD_ALIGN_PARAGRAPH.LEFT                                                              # 段落居中
            wd_comment.line_spacing = 1.0                                                                               # 行间距 注意用浮点数  2.0就表示两倍行间距
            #wd_comment.space_before = Pt(120)                                                                          # 段前间距
            #wd_comment.space_after = Pt(120)                                                                           # 段后间距

        # 正文表格插入
        df2['序号'] = range(1, len(df2) + 1)      # 添加序号
        df2 = pd.DataFrame(group, columns=['序号','字段英文名', '字段中文名','字段类型和长度','字段注释'])                       # 需要获取的字段数据
        table = document.add_table(rows=len(df2.index), cols=len(df2.columns),style='Table Grid')
        #table = document.add_table(rows=len(df2.index), cols=5)
        hdr_cells = table.rows[0].cells
        hdr_cells[0].text = '序号'
        hdr_cells[1].text = '字典英文名'
        hdr_cells[2].text = '字典中文名'
        hdr_cells[3].text = '类型'
        hdr_cells[4].text = '字段注释'
        table.add_row()
        for col0 in range(0,5):                                                                                         # 循环遍历单元格设置标题加粗
            table.rows[0].cells[col0].paragraphs[0].runs[0].font.size = Pt(10)
            table.rows[0].cells[col0].paragraphs[0].runs[0].font.bold = True
            table.rows[0].cells[col0].paragraphs[0].paragraph_format.line_spacing = 1.0
        '''
        #for i in range(len(df2.columns)):                                                                              # 添加表头
        #    table.cell(0, i).text = df2.columns[i]
        '''
        '''
        for row in range(0, len(df2.index)):                                                                            # 添加数据(此方法 效率比较慢)
            for col in range(len(df2.columns)):
                #table_value = str(df2.iloc[row, col])                                                                  # loc/iloc速度慢于at/iat
                table_value = str(df2.iat[row, col])                                                                    # loc/iloc速度慢于at/iat
                print('[',count_total,count,']>>RowTotal:[',len(df2.index),len(df2.columns)-1,']||row-->',row+1,'||col-->',col+1,'->>>',table_value)
                if table_value=='nan':
                    table_value = ''
                table.cell(row + 1, col).text = table_value                                                             # 表格数据
                # 设置表格单元格样式
                if table_value !='':
                    DwWordGet().TableCellStyle(row + 1, col, table)
        '''
        table_cells = table._cells
        for row in range(0, len(df2.index)):                                                                            # 添加数据（效率可以）
            row_cells = table_cells[(row+1)*5:(row+2)*5]
            for col in range(len(df2.columns)):
                table_value = str(df2.iat[row, col])                                                                    # loc/iloc速度慢于at/iat
                print(str(file_count),'>>[', count_total, count, ']>>RowTotal:[', len(df2.index), len(df2.columns) - 1, ']||row-->', row + 1, '||col-->', col + 1, '->>>', table_value)
                if table_value == 'nan':
                    table_value = ''
                row_cells[col].text = table_value                                                                       # 表格数据
        #document.add_page_break()                                                                                      # 分页
        DwWordGet().TableStyle(table)                                                                                  # 设置表格样式
        '''
        # 针对大文档分割处理
        '''
        if (count % 2500 == 1 and count!=1) or (count ==count_total) :                                                  # 2500页分割存一个文档
            bigCount = bigCount+1
            wd_fileName = str(file_res_dir + '\\' + system_nameV + '系统数据资源手册'+str(bigCount)+'.docx')
            document.save(wd_fileName)                                                                                  # 保存文档
            DwWordGet().DwWordCsh(system_nameV)                                                                         # 文档初始化
            document.add_page_break()

    # 设置表格样式
    def TableStyle(self,table):
        #table.style.paragraph_format.alignment = WD_TABLE_ALIGNMENT.CENTER                                             # 表格对齐方式| WD_TABLE_ALIGNMENT.LEFT | WD_TABLE_ALIGNMENT.RIGHT
        #table.cell(0, 0).width = Inches(1)
        table.style.font.size = Pt(10)
        #table.style.font.color.rgb = RGBColor(255, 0, 0)
        table.autofit = True                                                                                            # 表格自动适应窗口大小

        # 设置表格单元格样式
    def TableCellStyle(self, row, col, table):
        table.cell(row, col).width = 1
        table.cell(row, col).width = Cm(6)                                                                             # 表格宽度
        table.rows[row].cells[col].paragraphs[0].runs[0].font.size = Pt(10)
        table.rows[row].cells[col].paragraphs[0].paragraph_format.space_before = Pt(1)                                  # 段前间距
        table.rows[row].cells[col].paragraphs[0].paragraph_format.space_after = Pt(1)
        table.rows[row].cells[col].paragraphs[0].paragraph_format.line_spacing = 1
        table.rows[row].height = Cm(0.01)                                                                               # 表格高度


class Logger(object):
    level_relations = {
        'debug':logging.DEBUG,
        'info':logging.INFO,
        'warning':logging.WARNING,
        'error':logging.ERROR,
        'crit':logging.CRITICAL
    }#日志级别关系映射

    def __init__(self,filename,level='info',when='D',backCount=3,fmt='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
        self.logger = logging.getLogger(filename)
        format_str = logging.Formatter(fmt)#设置日志格式
        self.logger.setLevel(self.level_relations.get(level))#设置日志级别
        sh = logging.StreamHandler()#往屏幕上输出
        sh.setFormatter(format_str) #设置屏幕上显示的格式
        th = handlers.TimedRotatingFileHandler(filename=filename,when=when,backupCount=backCount,encoding='utf-8')#往文件里写入#指定间隔时间自动生成文件的处理器
        #实例化TimedRotatingFileHandler
        #interval是时间间隔，backupCount是备份文件的个数，如果超过这个个数，就会自动删除，when是间隔的时间单位，单位有以下几种：
        # S 秒
        # M 分
        # H 小时、
        # D 天、
        # W 每星期（interval==0时代表星期一）
        # midnight 每天凌晨
        th.setFormatter(format_str)#设置文件里写入的格式
        self.logger.addHandler(sh) #把对象加到logger里
        self.logger.addHandler(th)

def main():
    global document,wd_fileName,file_dir,bigCount,flag
    log = Logger(file_dir+'..\\Log\\'+'codeLog.log',level='debug')
    #Logger('error.log', level='error').logger.error('error')
    #log.logger.debug('debug')
    #log.logger.info('info')
    #log.logger.warning('警告')
    #log.logger.error('报错')
    #log.logger.critical('严重')

    file_count = 1
    # 获取目录下所有文件及文件名
    file_listS = DwFileNameGet().file_name()
    start = time.time()
    print('显示程序开始的时间:', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))

    # 遍历获取的文件名并获取Excel数据
    for index in range(0, len(file_listS)):
        # 获取文件名
        file_nameS = file_listS[index]
        # Excel处理
        if file_nameS.endswith(".xlsx"):
            startC = time.time()
            print('显示单表格程序开始的时间:', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
            DwExcelGet().DwExcelHandle(file_nameS,file_count)
            endC = time.time()
            print('显示单表格程序结束的时间:', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
            print('程序执行时间-->',endC - startC,'文件输出路径->>>',wd_fileName)
            log_str = '程序执行时间:'+str(endC - startC)+'>>文件输出路径:['+str(file_count)+']'+wd_fileName
            log.logger.info(log_str)
            if bigCount==0 and flag == 1:
                document.save(wd_fileName)
            wd_fileName = ''
            file_count = file_count + 1
            flag = 0
    end = time.time()
    print('显示程序结束的时间:', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
    print('程序执行总时间-->',end - start)
    log_strT = '程序执行完毕->>程序执行总时间:'+ str(end - start)
    log.logger.info(log_strT)


'''
# 执行入口
'''
if __name__ == '__main__':
    main()

